home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / Libraries / VideoToolbox 96.06.15 / VideoToolboxSources / IsNan.c < prev    next >
Text File  |  1996-03-07  |  6KB  |  143 lines

  1. /*
  2. IsNan.c
  3.  
  4. Fast, portable routines to check for IEEE transfinite numbers: INF and NAN. You
  5. should also look at the macro IsFinite() in VideoToolbox.h.
  6.  
  7. Apple's new header file fp.h defines the macros isfinite(x) and isnan(x), and
  8. the function nan("255"). At present the function nan() is only implemented for
  9. the PowerPC, but presumably Apple will soon extend support to include the 680x0
  10. machines too. Surprisingly, fp.h doesn't include any equivalent to IsInf(). You
  11. could write something like fpclassify(x)==FP_INFINITE, but getting the sign
  12. would take another step.
  13.  
  14. IsNan and IsInf take a shortcut in distinguishing NaN from INF. The definition
  15. of a NaN in the Apple Numerics book only says that a NaN is distinguished from
  16. an INF by having a nonzero mantissa. Unfortunately, a strict test of this
  17. requires testing the whole mantissa, up to 8 bytes, and in fact the routines in
  18. Plaugher's The Standard C Library do exactly this. (The IEEE standard ought to
  19. have disallowed a NaN code of zero.) We take a hybrid approach, on 680x0
  20. machines (i.e. 10 & 12 byte doubles) my experience is that the NaN code is
  21. always nonzero, unless someone goes out of their way to create a zero-code NaN,
  22. and what's more, in all NaNs the top bit of the mantissa is set. So it is
  23. sufficient to test the top bit and the code byte to distinguish between NaN and INF.
  24. On the other hand, the PowerPC Numerics manual says that the PowerPC chip always
  25. returns a NaN code of zero (seems a foolish choice), so we play safe and test
  26. the whole mantissa when we're dealing with 8 byte doubles.
  27.  
  28. The Numerical Extensions to C group has proposed in their draft standard that
  29. routines very similar to these become a part of Standard C. Anyone interested in
  30. writing such routines should read: Plauger, P. J. (1992) The Standard C Library.
  31. Englewood Cliffs, NJ: Prentice Hall.
  32.  
  33. PORTABILITY: Standard C. Should work on Motorola and Intel processors, but has
  34. only been tested on 680x0 and PowerPC processors in Macintosh computers.
  35.  
  36. HISTORY:
  37. 8/24/91 dgp    made compatible with THINK C 5.0.
  38. 12/23/91 dgp I replaced the #if statements by ordinary if statements, which are 
  39.     more readable and are allowed to use the sizeof() operator.
  40.     Note that most of the if statements will be evaluated and removed by the
  41.     compiler, with no runtime penalty.
  42. 12/23/91 dgp Wrote my own code to replace the SANE code since it's too slow.
  43.     This makes IsNan() about 5 times faster.
  44.     My code is based on the Apple Numerics Manual, 2nd edition. It says that
  45.     a number is a NAN iff the exponent is all ones and the fraction is nonzero.
  46.     I make a slight shortcut in checking only the top 15 bits of the fraction,
  47.     since that includes the byte that specifies the NAN type, on the premise
  48.     that all NANs that I will actually see in practice will have nonzero type.
  49.     My code handles the ordinary cases of 10 or 12 byte doubles. The weird
  50.     case of shorter doubles (which are unlikely since they run very slowly)
  51.     are detected by the assert() test at the beginning.
  52. 12/23/91 dgp Asked the THINK C compiler not to time this routine.
  53. 12/29/91 dgp Eliminated the need for SANE.h and Types.h. The SANE stuff
  54.     now appears in its own file: SANE.c. 
  55.     Wrote IsInf().
  56.     Wrote a new macro definition, in VideoToolbox.h, for IsFinite(), 
  57.     that allows fast inline testing for whether a number is ok, i.e. neither 
  58.     NAN nor INF. 
  59. 1/14/92    dgp    Changed IsNan() to now return the type (1..255) of the NAN, or zero
  60.     if not a NAN. This will break programs that assume the true value is always 1,
  61.     e.g. nans+=IsNan(a);
  62.     Fixed IsInf() to correctly return sign of ±INF.
  63. 1/18/92    dgp    Rewrote routines, making them simpler, and always checking the most 
  64.     significant bit of the mantissa in testing for NAN.
  65. 6/5/93    dgp    Updated documentation.
  66. 7/31/94 dgp added support for 8-byte doubles, to support the PowerPC.
  67. */
  68.  
  69. #include "VideoToolbox.h"
  70. #if (THINK_C || THINK_CPLUS || SYMANTEC_C)
  71.     #pragma options(!profile)    /* THINK C: attribute to the caller the time spent here. */
  72. #endif
  73. #define EXPONENT 0
  74. #define MANTISSA ((sizeof(double)-8)/2)
  75. int IsNan(double x);
  76. int IsInf(double x);
  77. #define zeroCode 21    /* NaN with zero code */
  78.  
  79. int IsNan(double x)
  80. /* Returns x's NAN type (1...255) or zero if x is not a NAN. */
  81. /* If NaN type is zero, return zeroCode. */
  82. {
  83.     register short i;
  84.     register unsigned long j;
  85.  
  86.     switch(sizeof(double)){
  87.     case 8:
  88.         j=((unsigned long *)&x)[0];
  89.         if((j & 0x7FF00000)==0x7FF00000){        /* either NAN or INF */
  90.             j&=0xFFFFF;                            /* mantissa */
  91.             if(j==0 && ((unsigned long *)&x)[1]==0)return 0;    /* INF */
  92.             i=j>>5;
  93.         }else return 0;
  94.         break;
  95.     case 10:
  96.     case 12:
  97.         if((((short *)&x)[EXPONENT] & 0x7FFF)==0x7FFF){        /* either NAN or INF */
  98.             i=((short *)&x)[MANTISSA] & 0x7FFF;
  99.             if(i==0)return 0;
  100.         }else return 0;
  101.         break;
  102.     default:
  103.         PrintfExit("%s line %d: Illegal sizeof(double)==%ld\n"
  104.             ,__FILE__,__LINE__,sizeof(double));
  105.     }
  106.     i&=0xFF;
  107.     if(i==0)i=zeroCode;
  108.     return i;
  109. }
  110.  
  111. int IsInf(double x)
  112. /* Returns -1 for -INF, 0 for not INF, and +1 for +INF. */
  113. {
  114.     register short i;
  115.     register long j;
  116.  
  117.     switch(sizeof(double)){
  118.     case 8:
  119.         j=((long *)&x)[0];
  120.         if((j & 0x7FF00000)==0x7FF00000){                    /* either NAN or INF */
  121.             if(j&0xFFFFF==0 && ((long *)&x)[1]==0){
  122.                 if(j<0)return -1;                            /*  -INF */
  123.                 else return 1;                                /*  +INF */
  124.             }
  125.         }
  126.         break;
  127.     case 10:
  128.     case 12:
  129.         i=((short *)&x)[EXPONENT];
  130.         if((i & 0x7FFF)==0x7FFF){                            /*  either NAN or INF */
  131.             if((((short *)&x)[MANTISSA] & 0x7FFF)==0){
  132.                 if(i<0)return -1;                            /*  -INF */
  133.                 else return 1;                                /*  +INF */
  134.             }
  135.         }
  136.         break;
  137.     default:
  138.         PrintfExit("%s line %d: Illegal sizeof(double)==%ld\n"
  139.             ,__FILE__,__LINE__,sizeof(double));
  140.     }
  141.     return 0;
  142. }
  143.